<template>
  <SearchForm
    v-show="isShowSearch"
    :search="search"
    :reset="reset"
    :columns="searchColumns"
    :search-param="searchParam"
    v-bind="{ ...defaultSearchConfig, ...searchConfig }"
  />

  <el-card class="table">
    <!-- 表格头部 操作按钮 -->
    <div class="table-header">
      <div class="header-button-lf">
        <slot
          name="tableHeader"
          :selected-list-ids="selectedListIds"
          :selected-list="selectedList"
          :is-selected="isSelected"
        ></slot>
      </div>
      <div v-if="toolButton" class="header-button-ri">
        <slot name="toolButton">
          <el-button :icon="Refresh" circle @click="getTableList" />
          <el-button
            v-if="columns.length"
            :icon="Printer"
            circle
            @click="print"
          />
          <el-button
            v-if="columns.length"
            :icon="Operation"
            circle
            @click="openColSetting"
          />
          <el-button
            v-if="searchColumns.length"
            :icon="Search"
            circle
            @click="isShowSearch = !isShowSearch"
          />
        </slot>
      </div>
    </div>
    <el-table
      :data="data || tableData"
      ref="tableRef"
      :max-height="props.maxHeight"
    >
      <template v-for="(item, index) in columns" :key="index">
        <el-table-column
          v-if="
            item?.tableItem?.type &&
            ['selection', 'index', 'expand'].includes(item?.tableItem?.type)
          "
          v-bind="item.tableItem"
          :align="item?.tableItem?.align ?? 'center'"
        >
        </el-table-column>
        <el-table-column
          v-else-if="item?.prop && item?.tableItem && !item.tableItem?.type"
          v-bind="item.tableItem"
          :align="item?.tableItem?.align ?? 'center'"
          :label="item.label"
          :prop="item.prop"
        >
          <!-- 内容插槽 -->
          <template #default="{ row }">
            <slot :name="handleProp(item.prop)" :row="row">
              <component
                :is="renderCellData(item, row)"
                v-if="item?.tableItem?.render"
              ></component>

              <template v-else>
                {{ renderCellData(item, row) }}
              </template>
            </slot>
          </template>

          <!-- 列标题插槽 -->
          <template #header="{ row }">
            <slot :name="`${handleProp(item.prop)}Header`" :row="row">
              <component
                v-if="item?.tableItem?.headerRender"
                :is="item?.tableItem?.headerRender?.(row)"
              ></component>

              <template v-else>
                {{ item.label }}
              </template>
            </slot>
          </template>
        </el-table-column>
      </template>
    </el-table>
  </el-card>
</template>

<script setup lang="ts" generic="T extends object">
import { ref } from "vue";
import type { TableType } from "../interface/";
import TableItem from "./TableItem.vue";
import SearchForm from "@/components/SearchForm/index.vue";
import { useTable } from "@/hooks/useTable";
import { Refresh, Printer, Operation, Search } from "@element-plus/icons-vue";
import printJS from "print-js";

const props = withDefaults(defineProps<TableType.Props<T>>(), {
  rowKey: "id",
  toolButton: true,
});
const tableRef = ref();
// 是否显示搜索模块
const isShowSearch = ref(true);

const defaultSearchConfig = {
  searchCol: { xs: 1, sm: 2, md: 2, lg: 3, xl: 3 },
};

// 过滤需要搜索的配置项
const searchColumns = props.columns.filter((item) => item.searchItem);

// 表格多选 Hooks
const { selectionChange, selectedList, selectedListIds, isSelected } =
  useSelection(props.rowKey);
// 表格操作 Hooks
const {
  tableData,
  pageable,
  searchParam,
  searchInitParam,
  getTableList,
  search,
  reset,
  handleSizeChange,
  handleCurrentChange,
} = useTable(
  props.requestApi,
  props.initParam,
  props.pagination,
  props.dataCallback,
  props.requestError
);

/**
 * @description 处理 prop，当 prop 为多级嵌套时 ==> 返回最后一级 prop
 * @param {String} prop 当前 prop
 * @returns {String}
 * */
function handleProp(prop: string) {
  const propArr = prop.split(".");
  if (propArr.length == 1) return prop;
  return propArr[propArr.length - 1];
}

/**
 * @description 处理 prop 为多级嵌套的情况，返回的数据 (列如: prop: user.name)
 * @param {Object} row 当前行数据
 * @param {String} prop 当前 prop
 * @returns {*}
 * */
function handleRowAccordingToProp(row: { [key: string]: any }, prop: string) {
  if (!prop.includes(".")) return row[prop] ?? "--";
  prop.split(".").forEach((item) => (row = row[item] ?? "--"));
  return row;
}

// 渲染表格数据，可做【定制】的数据渲染
const renderCellData = (item: TableType.TableItem, v: T) => {
  // h 函数
  if (typeof item.tableItem?.render === "function")
    return item.tableItem.render(v);

  // 默认数据
  return handleRowAccordingToProp(v, item.prop!);
};

// 🙅‍♀️ 不需要打印可以把以下方法删除，打印功能目前存在很多 bug
// 处理打印数据（把后台返回的值根据 enum 做转换）
const printData = computed(() => {
  const handleData = props.data ?? tableData.value;
  const printDataList = JSON.parse(
    JSON.stringify(selectedList.value.length ? selectedList.value : handleData)
  );
  // 找出需要转换数据的列（有 enum || 多级 prop && 需要根据 enum 格式化）
  const needTransformCol = flatColumns.value!.filter(
    (item) =>
      (item.enum || (item.prop && item.prop.split(".").length > 1)) &&
      item.isFilterEnum
  );
  needTransformCol.forEach((colItem) => {
    printDataList.forEach((tableItem: { [key: string]: any }) => {
      tableItem[handleProp(colItem.prop!)] =
        colItem.prop!.split(".").length > 1 && !colItem.enum
          ? formatValue(handleRowAccordingToProp(tableItem, colItem.prop!))
          : filterEnum(
              handleRowAccordingToProp(tableItem, colItem.prop!),
              enumMap.value.get(colItem.prop!),
              colItem.fieldNames
            );
      for (const key in tableItem) {
        if (tableItem[key] === null)
          tableItem[key] = formatValue(tableItem[key]);
      }
    });
  });
  return printDataList;
});

// 打印表格数据（💥 多级表头数据打印时，只能扁平化成一维数组，printJs 不支持多级表头打印）
const print = () => {
  const header = `<div style="text-align: center"><h2>${props.title}</h2></div>`;
  const gridHeaderStyle =
    "border: 1px solid #ebeef5;height: 45px;color: #232425;text-align: center;background-color: #fafafa;";
  const gridStyle =
    "border: 1px solid #ebeef5;height: 40px;color: #494b4e;text-align: center";
  printJS({
    printable: printData.value,
    header: props.title && header,
    properties: flatColumns
      .value!.filter(
        (item) =>
          !["selection", "index", "expand"].includes(item.type!) &&
          item.isShow &&
          item.prop !== "operation"
      )
      .map((item: ColumnsProps) => ({
        field: handleProp(item.prop!),
        displayName: item.label,
      })),
    type: "json",
    gridHeaderStyle,
    gridStyle,
  });
};

const getSelectionRows = () => {
  return tableRef.value.getSelectionRows();
};

// defineExpose({
//   getSelectionRows,
// });

// 暴露给父组件的参数和方法(外部需要什么，都可以从这里暴露出去)
defineExpose({
  element: tableRef,
  tableData,
  pageable,
  searchParam,
  searchInitParam,
  getTableList,
  search,
  reset,
  handleSizeChange,
  handleCurrentChange,
  // clearSelection,
  // enumMap,
  // isSelected,
  // selectedList,
  // selectedListIds,
});
</script>

<style lang="less">
.activeTable {
  --el-table-tr-bg-color: #f0f9eb;
}

.table {
  margin-top: 10px;
}
</style>
